www.gusucode.com > VC++ 五子棋包括网络版与单机版-源码程序 > VC++ 五子棋包括网络版与单机版-源码程序/code/Five/Game.cpp

    //Download by http://www.NewXing.com
#include "StdAfx.h"
#include "Table.h"
#include "Game.h"
#include "Messages.h"
#include "Resource.h"

//////////////////////////////////////////////////////////////////////////
// CGame类的实现部分
//////////////////////////////////////////////////////////////////////////
CGame::~CGame()
{
}
void CGame::Win( const STEP& stepSend )
{
}
//////////////////////////////////////////////////////////////////////////
// COneGame类的实现部分
//////////////////////////////////////////////////////////////////////////
COneGame::~COneGame()
{
}
void COneGame::Init()
{
    // 设置网络连接状态
    m_pTable->m_bConnected = FALSE;
    // 设置敌人姓名
    m_pTable->GetParent()->SetDlgItemText( IDC_ST_ENEMY, _T("计算机") );
    // 计算获胜组合情况
    int i, j, k, nCount = 0;
    for ( i = 0; i < 15; i++ )
    {
        for ( j = 0; j < 15; j++ )
        {
            for ( k = 0; k < 572; k++ )
            {
                m_Player[i][j][k] = false;
                m_Computer[i][j][k] = false;
            }
        }
    }
    for ( i = 0; i < 2; i++ )
    {
        for ( j = 0; j < 572; j++ )
        {
            m_Win[i][j] = 0;
        }
    }
    for ( i = 0; i < 15; i++ )
    {
        for ( j = 0; j < 11; j++ )
        {
            for ( k = 0; k < 5; k++ )
            {
                m_Player[j + k][i][nCount] = true;
                m_Computer[j + k][i][nCount] = true;
            }
            nCount++;
        }
    }
    for ( i = 0; i < 15; i++ )
    {
        for ( j = 0; j < 11; j++ )
        {
            for ( k = 0; k < 5; k++ )
            {
                m_Player[i][j + k][nCount] = true;
                m_Computer[i][j + k][nCount] = true;
            }
            nCount++;
        }
    }
    for ( i = 0; i < 11; i++ )
    {
        for ( j = 0; j < 11; j++ )
        {
            for ( k = 0; k < 5; k++ )
            {
                m_Player[j + k][i + k][nCount] = true;
                m_Computer[j + k][i + k][nCount] = true;
            }
            nCount++;
        }
    }
    for ( i = 0; i < 11; i++ )
    {
        for ( j = 14; j >= 4; j-- )
        {
            for ( k = 0; k < 5; k++ )
            {
                m_Player[j - k][i + k][nCount] = true;
                m_Computer[j - k][i + k][nCount] = true;
            }
            nCount++;
        }
    }
    if ( 1 == m_pTable->GetColor() )
    {
        // 如果玩家后走,则手动控制电脑占据天元
        m_pTable->SetData( 7, 7, 0 );
        PlaySound( MAKEINTRESOURCE( IDR_WAVE_PUT ), NULL, SND_RESOURCE | SND_SYNC );
        m_bStart = false;
        for ( i = 0; i < 572; i++ )
        {
            // 保存先前数据,做悔棋之用
            m_nOldWin[0][i] = m_Win[0][i];
            m_nOldWin[1][i] = m_Win[1][i];
            m_bOldPlayer[i] = m_Player[7][7][i];
        }
        for ( i = 0; i < 572; i++ )
        {
            // 修改计算机下子后,棋盘的变化状况
            if ( m_Computer[7][7][i] && m_Win[1][i] != -1 )
            {
                m_Win[1][i]++;
            }
            if ( m_Player[7][7][i] )
            {
                m_Player[7][7][i] = false;
                m_Win[0][i] = -1;
            }
        }
    }
    else
    {
        m_bStart = true;
    }
}
void COneGame::SendStep( const STEP& stepPut )
{
    int bestx, besty, i, j, pi, pj, ptemp, ctemp, pscore = 10, cscore = -10000;
    int ctempTable[15][15], ptempTable[15][15];
    int m, n, temp1[20], temp2[20]; // 暂存第一步搜索的信息

    m_pTable->GetParent()->GetDlgItem( IDC_BTN_BACK )->EnableWindow( FALSE );
    // 保存先前数据,做悔棋之用
    for ( i = 0; i < 572; i++)
    {
        m_nOldWin[0][i] = m_Win[0][i];
        m_nOldWin[1][i] = m_Win[1][i];
        m_bOldPlayer[i] = m_Player[stepPut.x][stepPut.y][i];
        m_bOldComputer[i] = m_Computer[stepPut.x][stepPut.y][i];
    }
    // 修改玩家下子后棋盘状态的变化
    for ( i = 0; i < 572; i++ )
    {
        // 修改状态变化
        if ( m_Player[stepPut.x][stepPut.y][i] && m_Win[0][i] != -1 )
            m_Win[0][i]++;
        if ( m_Computer[stepPut.x][stepPut.y][i] )
        {
            m_Computer[stepPut.x][stepPut.y][i] = false;
            m_Win[1][i] = -1;
        }
    }
    if ( m_bStart )
    {
        // 手动确定第一步:天元或(8, 8)
        if ( -1 == m_pTable->m_data[7][7] )
        {
            bestx = 7;
            besty = 7;
        }
        else
        {
            bestx = 8;
            besty = 8;
        }
        m_bStart = false;
    }
    else
    {
        STEP step;
        // 寻找最佳位置
        GetTable( ctempTable, m_pTable->m_data );
        while ( SearchBlank( i, j, ctempTable ) )
        {
            n = 0;
            pscore = 10;
            GetTable( ptempTable, m_pTable->m_data );
            ctempTable[i][j] = 2; // 标记已被查找
            step.color = 1 - m_pTable->GetColor();
            step.x = i;
            step.y = j;
            // 给这个空位打分
            ctemp = GiveScore( step );
            for ( m = 0; m < 572; m++ )
            {
                // 暂时更改玩家信息
                if ( m_Player[i][j][m] )
                {
                    temp1[n] = m;
                    m_Player[i][j][m] = false;
                    temp2[n] = m_Win[0][m];
                    m_Win[0][m] = -1;
                    n++;
                }
            }
            ptempTable[i][j] = 0;
            
            pi = i;
            pj = j;
            while ( SearchBlank( i, j, ptempTable ) )
            {
                
                ptempTable[i][j] = 2; // 标记已被查找
                step.color = m_pTable->GetColor();
                step.x = i;
                step.y = j;
                ptemp = GiveScore( step );
                if ( pscore > ptemp ) // 此时为玩家下子,运用极小极大法时应选取最小值
                    pscore = ptemp;
            }
            for ( m = 0; m < n; m++ )
            {
                // 恢复玩家信息
                m_Player[pi][pj][temp1[m]] = true;
                m_Win[0][temp1[m]] = temp2[m];
            }
            if ( ctemp + pscore > cscore ) // 此时为计算机下子,运用极小极大法时应选取最最大值
            {
                cscore = ctemp + pscore;
                bestx = pi;
                besty = pj;
            }
        }
    }
    m_step.color = 1 - m_pTable->GetColor();
    m_step.x = bestx;
    m_step.y = besty;
    for ( i = 0; i < 572; i++ )
    {
        // 修改计算机下子后,棋盘的变化状况
        if ( m_Computer[bestx][besty][i] && m_Win[1][i] != -1 )
            m_Win[1][i]++;
        if ( m_Player[bestx][besty][i] )
        {
            m_Player[bestx][besty][i] = false;
            m_Win[0][i] = -1;
        }
    }
    m_pTable->GetParent()->GetDlgItem( IDC_BTN_BACK )->EnableWindow();
    // 由于是单人游戏,所以直接接收数据
    m_pTable->Receive();
}
void COneGame::ReceiveMsg( MSGSTRUCT *pMsg )
{
    pMsg->color = m_step.color;
    pMsg->x = m_step.x;
    pMsg->y = m_step.y;
    pMsg->uMsg = MSG_PUTSTEP;
}
void COneGame::Back()
{
    int i;
    // 单人游戏直接允许悔棋
    STEP step;
    // 悔第一步(电脑落子)
    step = *( m_StepList.begin() );
    m_StepList.pop_front();
    m_pTable->m_data[step.x][step.y] = -1;
    // 恢复原有胜负布局
    for ( i = 0; i < 572; i++ )
    {
        m_Win[0][i] = m_nOldWin[0][i];
        m_Win[1][i] = m_nOldWin[1][i];
        m_Player[step.x][step.y][i] = m_bOldPlayer[i];
    }
    // 悔第二步(玩家落子)
    step = *( m_StepList.begin() );
    m_StepList.pop_front();
    m_pTable->m_data[step.x][step.y] = -1;
    // 恢复原有胜负布局
    for ( i = 0; i < 572; i++ )
    {
        m_Computer[step.x][step.y][i] = m_bOldComputer[i];
    }
    m_pTable->Invalidate();
    // 考虑到程序的负荷,这时候就不允许悔棋了
    AfxGetMainWnd()->GetDlgItem( IDC_BTN_BACK )->EnableWindow( FALSE );
}
int COneGame::GiveScore( const STEP& stepPut )
{
    int i, nScore = 0;
    for ( i = 0; i < 572; i++ )
    {
        if ( m_pTable->GetColor() == stepPut.color )
        {
            // 玩家下
            if ( m_Player[stepPut.x][stepPut.y][i] )
            {
                switch ( m_Win[0][i] )
                {
                case 1:
                    nScore -= 5;
                    break;
                case 2:
                    nScore -= 50;
                    break;
                case 3:
                    nScore -= 500;
                    break;
                case 4:
                    nScore -= 5000;
                    break;
                default:
                    break;
                }
            }
        }
        else
        {
            // 计算机下
            if ( m_Computer[stepPut.x][stepPut.y][i] )
            {
                switch ( m_Win[1][i] )
                {
                case 1:
                    nScore += 5;
                    break;
                case 2:
                    nScore += 50;
                    break;
                case 3:
                    nScore += 100;
                    break;
                case 4:
                    nScore += 10000;
                    break;
                default:
                    break;
                }
            }
        }
    }
    return nScore;
}
void COneGame::GetTable( int tempTable[][15], int nowTable[][15] )
{
    int i, j;
    for ( i = 0; i < 15; i++ )
    {
        for ( j = 0; j < 15; j++ )
        {
            tempTable[i][j] = nowTable[i][j];
        }
    }
}
bool COneGame::SearchBlank( int &i, int &j, int nowTable[][15] )
{
    int x, y;
    for ( x = 0; x < 15; x++ )
    {
        for ( y = 0; y < 15; y++ )
        {
            if ( nowTable[x][y] == -1 && nowTable[x][y] != 2 )
            {
                i = x;
                j = y;
                return true;
            }
        }
    }
    return false;
}
//////////////////////////////////////////////////////////////////////////
// CTwoGame类的实现部分
//////////////////////////////////////////////////////////////////////////
CTwoGame::~CTwoGame()
{
}
//////////////////////////////////////////////////////////////////////////
void CTwoGame::Init()
{
}
void CTwoGame::Win( const STEP& stepSend )
{
    SendStep( stepSend );
}
void CTwoGame::SendStep( const STEP& stepPut )
{
    MSGSTRUCT msg;
    msg.uMsg = MSG_PUTSTEP;
    msg.color = stepPut.color;
    msg.x = stepPut.x;
    msg.y = stepPut.y;

    m_pTable->m_conn.Send( (LPCVOID)&msg, sizeof( MSGSTRUCT ) );
}
void CTwoGame::ReceiveMsg( MSGSTRUCT *pMsg )
{
    int nRet = m_pTable->m_conn.Receive( pMsg, sizeof( MSGSTRUCT ) );
    if ( SOCKET_ERROR == nRet )
    {
        AfxGetMainWnd()->MessageBox( _T("接收数据时发生错误,请检查您的网络连接。"), _T("错误"), MB_ICONSTOP );
    }
}
void CTwoGame::Back()
{
    CDialog *pDlg = (CDialog *)AfxGetMainWnd();
    // 使按钮失效
    pDlg->GetDlgItem( IDC_BTN_BACK )->EnableWindow( FALSE );
    pDlg->GetDlgItem( IDC_BTN_HQ )->EnableWindow( FALSE );
    pDlg->GetDlgItem( IDC_BTN_LOST )->EnableWindow( FALSE );
    // 设置等待标志
    m_pTable->SetWait( TRUE );

    MSGSTRUCT msg;
    msg.uMsg = MSG_BACK;

    m_pTable->m_conn.Send( (LPCVOID)&msg, sizeof( MSGSTRUCT ) );
}